一般來說,我們在執行Java程式碼時,主要會經過以下階段:
除此之外,JVM在讀取byteCode,會自動去偵測程式中哪些方法頻繁被使用的,並針對這點去優化生成本機碼,這段是由JIT去執行的,JIT會針對被使用到多次的程式碼片段進行效能上的優化,這也是為什麼常常Java被人說需要先熱機。
講到JVM,我們就不得不提到Java的垃圾回收機制。
垃圾回收器的功用是為了將”沒被使用到”的資源回收,但怎麼去定義沒有被使用到的資源呢?最簡單的概念是沒有被引用到的資源,但怎樣算是沒有被引用到呢?這部分各程式語言都有不同的做法與認定的方式。以下僅簡單地用Python與Java來舉例:
Python的GC,是在Python內部建立一張判斷對象被引用的計數表,如果沒有被引用到 (count=0)時,GC就會把資源回收。它的好處是簡單直覺,效能高。( reachable vs unreachable )
但這種作法有兩個壞處,一個是計數器必須要找一個地方去存放(有多少份資源就有多少存入多少計數器),另一個問題是無法解決互相參照的情況。(ex:a = b, b = a,Python判斷有被參照到所以不回收)
Java的GC則比較不一樣, Java會自動挑出GC root(根節點),然後針對底下的物件去遍歷,若是沒有被遍歷到的則被視作Grabage,詳細可以參考以下這張圖。(referencable vs referencable )
這很大的一個程度上解決了Python GC的第二項缺點,但也代表一件事,Java在啟動時間會從根節點遍歷所有關連到的程式碼,這有一部分導致了Java沒辦法像其他程式一樣快。另外要提醒的是,GC清除資料的時間點是由JVM自己決定的,若是需要手動清除,則要使用 System.gc(); 手動清除垃圾。
而JVM針對清除垃圾的方式,也有不同的策略,請見以下說明:
以上,是有關GC內容,我的一些吸收與理解。希望能幫助其他人更好理解Java的運作。
參考資料:
https://www.gss.com.tw/eis/271-eis109/3513-eis109_9
https://www.jyt0532.com/2020/03/12/garbage-collector/